﻿namespace wwm.LeetCodeHelper;

/// <summary>
/// Abstract attribute which represents a data source for a data theory.
/// Data source providers derive from this attribute and implement GetData
/// to return the data for the theory.
/// Caution: the property is completely enumerated by .ToList() before any test is run. Hence it should return independent object sets.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class DataAttribute : Attribute
{
    /// <summary>
    /// Marks all test cases generated by this data source as skipped.
    /// </summary>
    public virtual string Skip
    {
        get;
        set;
    }

    /// <summary>
    /// 是否忽略列表的顺序
    /// </summary>
    public virtual bool IgnoreOrder
    {
        get;
        set;
    } = false;

    private static JsonSerializerOptions JsonSerializerOption = new JsonSerializerOptions()
    {
        AllowTrailingCommas = true,
        NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString
    };

    /// <summary>
    /// 将字符串格式化转换
    /// <para>因json没有单引号,如果有单引号需要转换成双引号且转义即:\"</para>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="s"></param>
    /// <returns></returns>
    public T StringTo<T>(string s)
    {
        if (s.Contains('\'')) s = s.Replace("'", "\"");
        var r = JsonSerializer.Deserialize<T>(s, JsonSerializerOption);
        return r;
    }
    /// <summary>
    /// 二进制字符串转 int 或 uint
    /// </summary>
    /// <typeparam name="T">int 或 uint</typeparam>
    /// <param name="s">二进制01表示的字符串: 00110001101</param>
    /// <param name="fromBase">二进制表示: 2 </param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public T BinaryStringTo<T>(string s, int fromBase = 2)
    {
        string typeName = typeof(T).Name.ToLower();
        return typeName switch
        {
            "uint" or "uint32" => (T)(object)Convert.ToUInt32(s, fromBase),
            "int" or "int32" => (T)(object)Convert.ToInt32(s, fromBase),
            _ => throw new ArgumentException(nameof(BinaryStringTo) + "未覆盖到该类型:" + typeName),
        };
    }
    /// <summary>
    /// 将一维数组转为N叉树Node
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public Node ToNodeWithString(string s)
    {
        int?[] nodeArray = JsonSerializer.Deserialize<int?[]>(s, JsonSerializerOption);
        if (nodeArray == null || nodeArray.Length == 0) return null;
        return NodeUtil.CreateNode(nodeArray);
    }
    /// <summary>
    /// 将一维数组转为ListNode
    /// <para>形如: [1,1,2,3,4,4]</para>
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public ListNode ToListNodeWithString(string s)
    {
        ListNode res = null;
        var list = JsonSerializer.Deserialize<List<int>>(s, JsonSerializerOption);
        if (list.Count == 0) return res;
        res = new ListNode();
        ListNode currentNode = res;
        for (int i = 0; i < list.Count(); i++)
        {
            if (i == 0) res.val = list[i];
            else
            {
                currentNode.next = new ListNode(list[i]);
                currentNode = currentNode.next;
            }
        }
        return res;
    }


    /// <summary>
    /// 将二维数组转换为 <![CDATA[ List<ListNode>() ]]>
    /// <para>形如: [[1,4,5],[1,3,4],[2,6]]</para>
    /// </summary>
    /// <param name="s"></param>
    /// <returns>List&lt;ListNode&gt;()</returns>
    public List<ListNode> ToListNodeListWithString(string s)
    {
        List<ListNode> res = new List<ListNode>();
        var list = JsonSerializer.Deserialize<List<List<int>>>(s, JsonSerializerOption);
        if (list.Count == 0) return res;
        for (var i = 0; i < list.Count(); i++)
        {
            ListNode resi = null;
            if (list[i].Count == 0) { res.Add(resi); continue; }
            resi = new ListNode();
            res.Add(resi);
            ListNode currentNode = resi;
            for (int j = 0; j < list[i].Count; j++)
            {
                if (j == 0) resi.val = list[i][j];
                else
                {
                    currentNode.next = new ListNode(list[i][j]);
                    currentNode = currentNode.next;
                }
            }
        }
        return res;
    }

    /// <summary>
    /// 字符串数组转TreeNode
    /// </summary>
    /// <param name="s"></param>
    /// <returns><see cref="TreeNode"/></returns>
    public TreeNode ToTreeNodeWithString(string s)
    {
        //处理s不是Array的情况
        if (!s.StartsWith("[") || !s.EndsWith("]"))
        {
            s = "[" + s + "]";
        }

        int?[] nodeArray = JsonSerializer.Deserialize<int?[]>(s, JsonSerializerOption);
        if (nodeArray == null || nodeArray.Length == 0) return null;

        return NodeUtil.CreateTree(nodeArray);
    }
    /// <summary>
    /// Returns the data to be used to test the theory.
    /// </summary>
    /// <returns>One or more sets of theory data. Each invocation of the test method
    /// is represented by a single object array.</returns>
    public abstract IEnumerable<object[]> GetData();
}

// Definition for a Node.
public class Node
{
    public int val;
    public IList<Node> children;

    public Node() { }

    public Node(int _val)
    {
        val = _val;
    }

    public Node(int _val, IList<Node> _children)
    {
        val = _val;
        children = _children;
    }
}

//Definition for singly-linked list.
/// <summary>
/// 单项节点ListNode
/// </summary>
public class ListNode
{
    public int val;
    public ListNode next;
    public ListNode(int val = 0, ListNode next = null)
    {
        this.val = val;
        this.next = next;
    }
    /// <summary>
    /// 自定义ToString 使用'-'显示
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        List<int> s = new List<int>();
        GetVal(this, s);
        return string.Join("-", s);
    }

    private void GetVal(ListNode ln, List<int> s)
    {
        //循环引用了
        if (ln == ln.next) return;
        if (ln != null) s.Add(ln.val);
        if (ln != null && ln.next != null) GetVal(ln.next, s);
    }
}


//Definition for a binary tree node.
public class TreeNode
{
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val = 0, TreeNode left = null, TreeNode right = null)
    {
        this.val = val;
        this.left = left;
        this.right = right;
    }

    public override string ToString()
    {
        List<int> ints = new List<int>();
        //使用中序遍历形成数组的形式
        NodeUtil.MidDfs(this, ints);
        return ints.ToJson();
    }


}

/// <summary>
/// 二叉树帮助类
/// </summary>
public static class NodeUtil
{
    /// <summary>
    /// 创建N叉树, 原始数据按层序遍历序列化表示,每组子节点由空值分隔
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static Node CreateNode(int?[] arr)
    {
        if (arr.Length == 0 || arr[0] == null) return null;
        Node root = new Node((int)arr[0]);
        Queue<Node> queue = new Queue<Node>();
        queue.Enqueue(root);
        int index = 1;
        while (queue.Count > 0)
        {
            index++;
            Node node = queue.Dequeue();
            if (node == null) continue;
            if (index >= arr.Length) break;
            node.children = new List<Node>();
            while (index < arr.Length && arr[index] != null)
            {
                Node childrenNode = new Node((int)arr[index]);
                queue.Enqueue(childrenNode);
                node.children.Add(childrenNode);
                index++;
            }
        }
        return root;
    }

    public static TreeNode CreateTreeNodeNode(int? val)
    {
        if (val == null) return null;
        return new TreeNode((int)val);
    }
    /// <summary>
    /// 创建TreeNode, 使用按层序遍历方法,只有left和right两个子节点
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static TreeNode CreateTree(int?[] arr)
    {
        if (arr.Length == 0 || arr[0] == null) return null;
        TreeNode root = NodeUtil.CreateTreeNodeNode(arr[0]);
        Queue<TreeNode> queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        int index = 1;
        while (queue.Count > 0)
        {
            TreeNode node = queue.Dequeue();
            if (node == null) continue;
            if (index < arr.Length)
            {
                node.left = NodeUtil.CreateTreeNodeNode(arr[index++]);
                queue.Enqueue(node.left);
            }
            if (index < arr.Length)
            {
                node.right = NodeUtil.CreateTreeNodeNode(arr[index++]);
                queue.Enqueue(node.right);
            }
        }
        return root;
    }

    /// <summary>
    /// 中序遍历
    /// </summary>
    /// <param name="o"></param>
    /// <param name="nodeValList"></param>
    public static void MidDfs(TreeNode o, List<int> nodeValList)
    {
        if (o == null)
        {
            //nodeValList.Add(0);
            return;
        };
        MidDfs(o.left, nodeValList);
        nodeValList.Add(o.val);
        MidDfs(o.right, nodeValList);
    }


}
